﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Server.ProjectHelpers;




namespace Server
{
    public class Controller
    {

        protected ServerDataBaseContainer _connection;

        protected QueueManager _queue;

        protected ProjectController _projectsController;

        public Controller()
        {
            _connection = new ServerDataBaseContainer();
            _queue = new QueueManager(_connection);
            _projectsController = new ProjectController();
        }

        /// <summary>
        /// Registers the computing unit.
        /// </summary>
        /// <param name="processor">The processor.</param>
        /// <returns>Guid.</returns>
        public Guid RegisterComputingUnit(Processor processor, string ip)
        {
            Guid newId = Guid.NewGuid();
            var unit = new CompiutingUnits()
            {
                Guid = newId,
                JoinDate = DateTime.Now,
                LastActivityDate = DateTime.Now,
                LastIP = ip,
                Processor = processor
            };

            _connection.CompiutingUnitsSet.AddObject(unit);
            _connection.SaveChanges();
            return newId;
        }

        public void AddProject(string name)
        {
            _projectsController.AddNew(name);
        }

        public LibInterface.Compiuting GetNextCompiutingData(Guid userId, int skip = 0)
        {
            LibInterface.Compiuting computing;
            var failCompiuting = _connection.CompiutingSet.FirstOrDefault(c => c.CompiutingStatus.Id == (short)CompiutingStatuses.ToRenew && c.StartDate.AddDays((double)c.Project.MaxDaysOfCompiuting) < DateTime.Now);
            if (failCompiuting == null)
            {
                computing = _projectsController.RequestCompiutingData(projectId);
            }
            
            int projectId;
            try
            {
                try
                {
                    projectId = _queue.GetFavoriteProjectId(userId, skip);
                }
                catch (Exception ex)
                {

                    Logger.Instance.Log(ex);
                    return new LibInterface.Compiuting();

                }
                computing = _projectsController.RequestCompiutingData(projectId);
            }
            catch (NoDataComputingExeption ex)
            {
                computing = this.GetNextCompiutingData(userId, skip + 1);
                Logger.Instance.Log(ex);
                throw;
            }


            AddCompiutingToDataBase(userId, projectId);

            return computing;
        }

        private void AddCompiutingToDataBase(Guid userId, int projectId)
        {
            _connection.CompiutingSet.AddObject(new Compiuting
            {
                CompiutingStatus = _connection.CompiutingStatusSet.First(s => s.Id == (int)CompiutingStatuses.InProgress),
                StartDate = DateTime.Now,
                CompiutingUnits = _connection.CompiutingUnitsSet.First(u => u.Guid == userId),
                Project = _connection.ProjectSet.First(p => p.Id == projectId)
            });
            _connection.SaveChanges();
        }

        public byte[] GetParamiter(int projectId, int parameterId, bool isDynamic)
        {
            return this._projectsController.GetParamiter(projectId, parameterId, isDynamic);
        }


        public object GetProjects()
        {
            return _connection
                .ProjectSet
                .Select(p => new DTO.ProjectDTO
                {
                    Id = p.Id,
                    Name = p.Name,
                    Priorytet = p.Priorytet,
                    AddDate = p.AddDate,
                    EndDate = p.EndDate,
                    Status = p.Status.Name
                })
                .ToList();
        }

        public void AddProjectObserver(int projectId, GUI.ProjectObserver projectObserver)
        {
            this._projectsController.AddObserver(projectId, projectObserver);
        }

        public object GetComputingUnits()
        {
            return _connection.CompiutingUnitsSet
                .OrderBy(c => c.LastActivityDate)
                .Select(u => new DTO.UnitDTO
                {
                    Id = u.Guid,
                    JoinDate = u.JoinDate,
                    LastActivity = u.LastActivityDate,
                    IP = u.LastIP,
                    Procesor = u.Processor.Name,
                    Cores = u.Processor.LogicalProcess,
                    Computing = u.Compiuting.Count(),
                    ComputingActive = u.Compiuting
                        .Count(com => com.CompiutingStatus.Id == (short)CompiutingStatuses.InProgress),
                    Projects = u.Compiuting
                        .GroupBy(com => new { ProjectID = com.Project.Id })
                        .Count()
                })
                .ToList();
        }

        public List<DTO.ComputingDTO> GetComputing()
        {
            return _connection.CompiutingSet
                .OrderBy(c => c.StartDate)
                .OrderBy(c => c.CompiutingStatus.Id)
                .Select(c => new DTO.ComputingDTO
                {
                    Id = c.Id,
                    Status = c.CompiutingStatus.Name,
                    Project = c.Project.Name,
                    StartDate = c.StartDate,
                    EndDate = c.EndDate
                })
                .ToList();
        }

        public void SetPriorytet(int projectId, byte priorytet)
        {
            var project = _connection.ProjectSet.First(p => p.Id == projectId);
            project.Priorytet = priorytet;
            _connection.SaveChanges();
        }

        public bool IsExistUnit(Guid unitId)
        {
            if (_connection.CompiutingUnitsSet.Any(u => u.Guid == unitId))
            {
                var unit = _connection.CompiutingUnitsSet.First(u => u.Guid == unitId);
                unit.LastActivityDate = DateTime.Now;
                _connection.SaveChanges();
                return true;
            }
            else
            {
                return false;
            }
        }

        public List<Services.DTO.ProjectDTOBasic> GetActiveProjects()
        {
            return _connection.ProjectSet.Where(p => p.Status.Id == (int)ProjestStatuses.Active)
                .Select(p => new Services.DTO.ProjectDTOBasic
                {
                    Name = p.Name,
                    ProjectId = p.Id
                })
                .ToList();

        }

        public List<Services.DTO.ProjectFilesDTO> GetProjectFiles(int projectId)
        {
            return _projectsController.GetProjectFiles(projectId);
        }
    }
}
